import { ref, onMounted, nextTick } from 'vue'
import type { RouteLocationNormalized } from 'vue-router'

// 预加载策略配置
interface PreloadConfig {
  // 预加载时机
  trigger: 'idle' | 'visible' | 'hover' | 'immediate'
  // 优先级
  priority: 'high' | 'low' | 'auto'
  // 资源类型
  type: 'script' | 'style' | 'image' | 'font' | 'route'
  // 延迟时间
  delay?: number
  // 是否跨域
  crossOrigin?: boolean
  // 完整性校验
  integrity?: string
}

// 资源预加载管理器
export class ResourcePreloader {
  private preloadedResources = new Set<string>()
  private preloadPromises = new Map<string, Promise<void>>()
  private observer: IntersectionObserver | null = null

  constructor() {
    this.setupIntersectionObserver()
  }

  // 设置可见性观察器
  private setupIntersectionObserver() {
    if ('IntersectionObserver' in window) {
      this.observer = new IntersectionObserver(
        (entries) => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              const element = entry.target as HTMLElement
              const url = element.dataset.preloadUrl
              const type = element.dataset.preloadType as PreloadConfig['type']
              
              if (url && type) {
                this.preloadResource(url, { trigger: 'visible', priority: 'auto', type })
                this.observer?.unobserve(element)
              }
            }
          })
        },
        { rootMargin: '50px' }
      )
    }
  }

  // 预加载资源
  async preloadResource(url: string, config: PreloadConfig): Promise<void> {
    if (this.preloadedResources.has(url)) {
      return Promise.resolve()
    }

    if (this.preloadPromises.has(url)) {
      return this.preloadPromises.get(url)!
    }

    const promise = this.createPreloadPromise(url, config)
    this.preloadPromises.set(url, promise)
    
    try {
      await promise
      this.preloadedResources.add(url)
    } catch (error) {
      console.warn(`预加载失败: ${url}`, error)
      this.preloadPromises.delete(url)
    }

    return promise
  }

  // 创建预加载Promise
  private createPreloadPromise(url: string, config: PreloadConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      // 延迟执行
      const executePreload = () => {
        switch (config.type) {
          case 'script':
            this.preloadScript(url, config).then(resolve).catch(reject)
            break
          case 'style':
            this.preloadStyle(url, config).then(resolve).catch(reject)
            break
          case 'image':
            this.preloadImage(url, config).then(resolve).catch(reject)
            break
          case 'font':
            this.preloadFont(url, config).then(resolve).catch(reject)
            break
          default:
            this.preloadGeneric(url, config).then(resolve).catch(reject)
        }
      }

      if (config.delay) {
        setTimeout(executePreload, config.delay)
      } else {
        executePreload()
      }
    })
  }

  // 预加载脚本
  private preloadScript(url: string, config: PreloadConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      // 首先创建预加载链接
      const preloadLink = document.createElement('link')
      preloadLink.rel = 'preload'
      preloadLink.as = 'script'
      preloadLink.href = url
      
      if (config.crossOrigin) {
        preloadLink.crossOrigin = 'anonymous'
      }
      
      if (config.integrity) {
        preloadLink.integrity = config.integrity
      }

      preloadLink.onload = () => resolve()
      preloadLink.onerror = () => reject(new Error(`Script preload failed: ${url}`))
      
      document.head.appendChild(preloadLink)
    })
  }

  // 预加载样式
  private preloadStyle(url: string, config: PreloadConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'preload'
      link.as = 'style'
      link.href = url
      
      if (config.crossOrigin) {
        link.crossOrigin = 'anonymous'
      }
      
      if (config.integrity) {
        link.integrity = config.integrity
      }

      link.onload = () => {
        // 创建实际的样式链接
        const styleLink = document.createElement('link')
        styleLink.rel = 'stylesheet'
        styleLink.href = url
        if (config.crossOrigin) styleLink.crossOrigin = 'anonymous'
        if (config.integrity) styleLink.integrity = config.integrity
        
        document.head.appendChild(styleLink)
        resolve()
      }
      
      link.onerror = () => reject(new Error(`Style preload failed: ${url}`))
      document.head.appendChild(link)
    })
  }

  // 预加载图片
  private preloadImage(url: string, config: PreloadConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      const img = new Image()
      img.onload = () => resolve()
      img.onerror = () => reject(new Error(`Image preload failed: ${url}`))
      
      if (config.crossOrigin) {
        img.crossOrigin = 'anonymous'
      }
      
      img.src = url
    })
  }

  // 预加载字体
  private preloadFont(url: string, config: PreloadConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'preload'
      link.as = 'font'
      link.type = 'font/woff2'
      link.href = url
      link.crossOrigin = 'anonymous'

      link.onload = () => resolve()
      link.onerror = () => reject(new Error(`Font preload failed: ${url}`))
      
      document.head.appendChild(link)
    })
  }

  // 通用预加载
  private preloadGeneric(url: string, config: PreloadConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'prefetch'
      link.href = url
      
      if (config.crossOrigin) {
        link.crossOrigin = 'anonymous'
      }

      link.onload = () => resolve()
      link.onerror = () => reject(new Error(`Generic preload failed: ${url}`))
      
      document.head.appendChild(link)
    })
  }

  // 观察元素以触发可见性预加载
  observeElement(element: HTMLElement, url: string, type: PreloadConfig['type']) {
    if (this.observer) {
      element.dataset.preloadUrl = url
      element.dataset.preloadType = type
      this.observer.observe(element)
    }
  }

  // 清理资源
  destroy() {
    this.observer?.disconnect()
    this.preloadPromises.clear()
    this.preloadedResources.clear()
  }
}

// 路由预加载器
export class RoutePreloader {
  private routeComponents = new Map<string, Promise<any>>()
  private preloadedRoutes = new Set<string>()

  // 预加载路由组件
  async preloadRoute(routePath: string): Promise<void> {
    if (this.preloadedRoutes.has(routePath)) {
      return Promise.resolve()
    }

    if (this.routeComponents.has(routePath)) {
      return this.routeComponents.get(routePath)!
    }

    try {
      // 这里需要根据实际路由配置来动态导入
      const componentPromise = this.getRouteComponent(routePath)
      this.routeComponents.set(routePath, componentPromise)
      
      await componentPromise
      this.preloadedRoutes.add(routePath)
    } catch (error) {
      console.warn(`路由预加载失败: ${routePath}`, error)
      this.routeComponents.delete(routePath)
    }
  }

  // 获取路由组件（需要根据实际路由配置调整）
  private getRouteComponent(routePath: string): Promise<any> {
    // 简化版本，实际应用中需要根据路由表动态匹配
    const routeMap: Record<string, () => Promise<any>> = {
      '/': () => import('../views/sow/Home.vue'),
      '/department-select': () => import('../views/sow/DepartmentSelect.vue'),
      '/hospital-select': () => import('../views/sow/HospitalSelect.vue'),
      '/doctor-select': () => import('../views/sow/DoctorSelect.vue'),
      '/about': () => import('../views/About.vue')
    }

    const componentLoader = routeMap[routePath]
    if (componentLoader) {
      return componentLoader()
    }

    return Promise.reject(new Error(`未找到路由组件: ${routePath}`))
  }

  // 预加载相关路由
  async preloadRelatedRoutes(currentRoute: RouteLocationNormalized): Promise<void> {
    const relatedRoutes = this.getRelatedRoutes(currentRoute.path)
    const preloadPromises = relatedRoutes.map(route => this.preloadRoute(route))
    
    try {
      await Promise.allSettled(preloadPromises)
    } catch (error) {
      console.warn('批量预加载路由失败:', error)
    }
  }

  // 获取相关路由（基于业务逻辑）
  private getRelatedRoutes(currentPath: string): string[] {
    const relationMap: Record<string, string[]> = {
      '/': ['/department-select', '/hospital-select'],
      '/department-select': ['/hospital-select', '/doctor-select'],
      '/hospital-select': ['/doctor-select'],
      '/doctor-select': ['/']
    }

    return relationMap[currentPath] || []
  }
}

// 智能预加载策略composable
export function usePreloadStrategy() {
  const resourcePreloader = ref<ResourcePreloader | null>(null)
  const routePreloader = ref<RoutePreloader | null>(null)
  const preloadStats = ref({
    resourcesPreloaded: 0,
    routesPreloaded: 0,
    totalSavedTime: 0
  })

  onMounted(() => {
    resourcePreloader.value = new ResourcePreloader()
    routePreloader.value = new RoutePreloader()
  })

  // 预加载关键资源
  const preloadCriticalResources = async () => {
    if (!resourcePreloader.value) return

    const criticalResources = [
      // 字体
      { url: '/fonts/main.woff2', type: 'font' as const, priority: 'high' as const },
      // 关键样式
      { url: '/css/critical.css', type: 'style' as const, priority: 'high' as const },
      // 首屏图片
      { url: '/images/hero-bg.jpg', type: 'image' as const, priority: 'high' as const }
    ]

    const promises = criticalResources.map(resource =>
      resourcePreloader.value!.preloadResource(resource.url, {
        trigger: 'immediate',
        priority: resource.priority,
        type: resource.type
      })
    )

    try {
      await Promise.allSettled(promises)
      preloadStats.value.resourcesPreloaded += criticalResources.length
    } catch (error) {
      console.warn('关键资源预加载失败:', error)
    }
  }

  // 智能预加载（基于用户行为）
  const smartPreload = async (element: HTMLElement, url: string, type: PreloadConfig['type']) => {
    if (!resourcePreloader.value) return

    // 检测用户连接质量
    const connection = (navigator as any).connection
    if (connection && connection.saveData) {
      // 用户开启了数据节省模式，跳过预加载
      return
    }

    const config: PreloadConfig = {
      trigger: 'hover',
      priority: connection?.effectiveType === '4g' ? 'high' : 'low',
      type
    }

    await resourcePreloader.value.preloadResource(url, config)
  }

  // 鼠标悬停预加载
  const onHoverPreload = (element: HTMLElement, url: string, type: PreloadConfig['type']) => {
    let timeoutId: number

    const handleMouseEnter = () => {
      timeoutId = window.setTimeout(() => {
        smartPreload(element, url, type)
      }, 100) // 100ms延迟，避免误触
    }

    const handleMouseLeave = () => {
      clearTimeout(timeoutId)
    }

    element.addEventListener('mouseenter', handleMouseEnter)
    element.addEventListener('mouseleave', handleMouseLeave)

    // 返回清理函数
    return () => {
      element.removeEventListener('mouseenter', handleMouseEnter)
      element.removeEventListener('mouseleave', handleMouseLeave)
      clearTimeout(timeoutId)
    }
  }

  // 空闲时预加载
  const preloadOnIdle = async (resources: Array<{ url: string; type: PreloadConfig['type'] }>) => {
    if (!resourcePreloader.value) return

    const preload = async () => {
      for (const resource of resources) {
        await resourcePreloader.value!.preloadResource(resource.url, {
          trigger: 'idle',
          priority: 'low',
          type: resource.type
        })
        preloadStats.value.resourcesPreloaded++
      }
    }

    if ('requestIdleCallback' in window) {
      requestIdleCallback(preload, { timeout: 5000 })
    } else {
      // 降级到 setTimeout
      setTimeout(preload, 100)
    }
  }

  // 可见性预加载
  const preloadOnVisible = (element: HTMLElement, url: string, type: PreloadConfig['type']) => {
    if (resourcePreloader.value) {
      resourcePreloader.value.observeElement(element, url, type)
    }
  }

  // 预加载统计
  const getPreloadStats = () => preloadStats.value

  return {
    preloadCriticalResources,
    smartPreload,
    onHoverPreload,
    preloadOnIdle,
    preloadOnVisible,
    getPreloadStats,
    resourcePreloader: resourcePreloader.value,
    routePreloader: routePreloader.value
  }
}

// 预加载指令
export const vPreload = {
  mounted(el: HTMLElement, binding: any) {
    const { url, type = 'script', trigger = 'hover' } = binding.value || {}
    
    if (!url) {
      console.warn('v-preload 指令需要 url 参数')
      return
    }

    const { onHoverPreload, preloadOnVisible } = usePreloadStrategy()

    switch (trigger) {
      case 'hover':
        onHoverPreload(el, url, type)
        break
      case 'visible':
        preloadOnVisible(el, url, type)
        break
      case 'immediate':
        // 立即预加载
        nextTick(() => {
          const resourcePreloader = new ResourcePreloader()
          resourcePreloader.preloadResource(url, {
            trigger: 'immediate',
            priority: 'auto',
            type
          })
        })
        break
    }
  }
} 